package com.service.healthycode.service.impl;

import com.service.config.utils.*;
import com.service.healthycode.dao.InfoDeclareDao;
import com.service.healthycode.dao.UserDao;
import com.service.healthycode.dto.InfoDeclareDto;
import com.service.healthycode.dto.SmsCode;
import com.service.healthycode.entity.InfoDeclare;
import com.service.healthycode.entity.UserInfo;
import com.service.healthycode.rabbitmq.MsgProducer;
import com.service.healthycode.service.DangerUserService;
import com.service.healthycode.service.InfoDeclareService;
import com.service.healthycode.vo.QueryByMacVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author: hjl
 * @date: 2022/05/12 18:26
 * @description:
 */
@Service
@Slf4j
public class InfoDeclareServiceImpl implements InfoDeclareService {
    @Resource
    private InfoDeclareDao infoDeclareDao;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private MsgProducer msgProducer;
    @Resource
    private UserDao userDao;
    @Resource
    private DangerUserService dangerUserService;

    private static final String redisKey = "user:info:healthycode:infodeclare:";

    /**
     * 填写信息申报信息
     * @param infoDeclare
     * @param uid
     * @return
     * @throws Exception
     */
    @Override
    public Result addInfoDeclare(InfoDeclareDto infoDeclare, String uid) throws Exception {
        infoDeclare.setId(IdUtil.getStringId());
        infoDeclare.setFillTime(DateUtils.getNowDate());
        infoDeclare.setUId(uid);
        infoDeclare.setUpdateTime(DateUtils.getNowDate());
        InfoDeclare infoDeclare1 = ModelMapperUtil.strictMap(infoDeclare, InfoDeclare.class);
        infoDeclareDao.addInfoDeclare(infoDeclare1);

        //根据用户申报信息，判断用户健康状态
        Integer status = this.checkStatus(infoDeclare1);
        userDao.updateStatusByTel(infoDeclare1.getTelephone(),status);

        if (redisUtil.exist(redisKey+infoDeclare.getTelephone())){
            redisUtil.delete(redisKey+infoDeclare.getTelephone());
        }
        redisUtil.set(redisKey+infoDeclare.getTelephone(), 4,JsonXMLUtils.obj2json(infoDeclare), Long.valueOf(14*24));
        return Result.ok();
    }


    /**
     * 查询用户最近一次的申报信息
     * @param userId
     * @return
     */
    @Override
    public InfoDeclare queryInfoDeclare(String userId) {
        InfoDeclare infoDeclare = infoDeclareDao.queryInfoDeclare(userId);
        return infoDeclare;
    }

    /**
     * 查询用户申报信息是否过期
     * @param userId
     * @return
     */
    @Override
    public Result queryInfoExpired(String userId) {
        if (redisUtil.exist(redisKey+userId)){
            return Result.ok().setData(true);
        }
        return Result.failure("申报信息已过期，请重新申报!");
    }

    /**
     * 更新信息申报
     * @param infoDeclare 申报信息
     * @param userId 用户id
     * @return
     */
    @Override
    public Result updateInfoDeclare(InfoDeclareDto infoDeclare, String userId) throws Exception {
        infoDeclare.setUId(userId);
        infoDeclare.setUpdateTime(DateUtils.getNowDate());
        InfoDeclare infoDeclare1 = ModelMapperUtil.strictMap(infoDeclare, InfoDeclare.class);
        infoDeclareDao.updateInfoDeclare(infoDeclare1);

        //根据用户申报信息，判断用户健康状态
        Integer status = this.checkStatus(infoDeclare1);
        userDao.updateStatusByTel(infoDeclare1.getTelephone(), status);

        if (redisUtil.exist(redisKey + infoDeclare.getTelephone())) {
            redisUtil.delete(redisKey + infoDeclare.getTelephone());
        }
        redisUtil.sets(redisKey + infoDeclare.getTelephone(), JsonXMLUtils.obj2json(infoDeclare), Long.valueOf(14 * 24));
        return Result.ok();

    }

    /**
     * 校验申报信息结果
     * @return 状态码:终端状态:4->红码;3->黄码;2->绿码;1->灰码
     */
    public Integer checkStatus(InfoDeclare infoDeclare){
        if (infoDeclare.getIsTouch()==true
        || infoDeclare.getIsHealthy()==true){
            return 4;
        }
        if (infoDeclare.getWithHealthy() != null){
            if (infoDeclare.getIsHealthy()==true){
                return 4;
            }
        }
        return 2;
    }

    @Override
    public Result sendSms(SmsCode smsCode)  {
        String code = verifyCode(smsCode.getTelephone(),6);
        smsCode.setCode(code);
        try {
            msgProducer.sendMsg(smsCode);
            return Result.ok();
        } catch (Exception e) {
            e.printStackTrace();
            return Result.failure("123444");
        }
    }

    /**
     * 查询用户健康码状态
     * @param terminalMac
     * @param userId
     * @return
     */
    @Override
    public Result queryStatus(String terminalMac, String userId) {
        Integer status = 1;
        Integer code = dangerUserService.queryByMac(terminalMac).getCode();
        UserInfo userInfo = userDao.queryUserById(userId);
        if (userInfo != null && userInfo.getStatus() != null){
            status = userInfo.getStatus();
        }
        if (code.equals(200)){
            List<QueryByMacVo> vos = (List<QueryByMacVo>) dangerUserService.queryByMac(terminalMac).getData();
            if (!vos.isEmpty()){
                Integer macStatus = vos.get(0).getStatus();
                if (status==4 || macStatus==3 || macStatus==4){
                    //红码
                    return Result.ok().setData(4);
                }else if(macStatus == 2 || macStatus == 1 || status == 3){
                    //黄码
                    return Result.ok().setData(3);
                }else if(macStatus == 0 || status ==2){
                    //绿码
                    return Result.ok().setData(2);
                }else if(status == 1){
                    //灰码
                    return Result.ok().setData(1);
                }
            }
        }
        return Result.ok().setData(status);
    }

    /**
     * 验证本地是否存在重复验证码，如重复，则重新生成
     * @param tel
     * @param integer
     * @return
     */
    private String verifyCode(String tel,Integer integer) {
        String randomNum = CharUtil.getRandomNum(integer);
        if (redisUtil.exist(randomNum)) {
            verifyCode(tel,integer);
        }
        redisUtil.set(randomNum,1,tel,5);
        return randomNum;
    }
}
